﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CSharp.Libs.ExceptionHandling;
using System.Collections;
using CSharp.Libs.Net;
using CSharp.Libs.Koc.KernelModels;

namespace CSharp.Libs.Koc.Models
{
    public static class PhpCommandGenerator
    {
        #region declarations
        //base data
        private static String _strPhpUrlPrefix = "";
        private static String _strPhpUrlDirs = "";

        private static Dictionary<string, UserValidatorItem> _dictUsers = new Dictionary<string, UserValidatorItem>();

        #region events
        public delegate void NewUserReceivedEventHandler(object sender, NewUserReceivedEventArgs nuvea);
        public static event NewUserReceivedEventHandler NewUserReceived;
        private static void ThrowNewUserReceivedEvent(
            NewUserReceivedEventArgs nuvea)
        {
            if (NewUserReceived != null)
            {
                NewUserReceived(typeof(PhpCommandGenerator), nuvea);
            }
        }
        #endregion
        #endregion



        #region private functions
        #region initialization
        /// <summary>_AnalyseUrlGetChat</summary>
        /// <param name="GetChatUrl"></param>
        /// <remarks>moved together functionality of URLHolder an URItem. Formerly the complete URL was given
        /// to UH and was split to URL and parameter part. URL part was given to URLItem and was analyzed there. 
        /// Parameter dict was filled right in UH. All is done here in one place now.</remarks>
        /// <history>created  15.01.2012</history>
        private static bool _AnalyseUrlGetChat(
            string GetChatUrl,
            string GetChatPostData)
        {
            // split apart url part and get parameters out of PostData
            _GetUrlPart(GetChatUrl);
            BaseParameters = _GetParameterDictionary(GetChatPostData);

            // remove getChat specific parameters to have fb basic parameters left
            _RemoveGetChatSpecificParameters();

            // set IsInitialized bool
            IsInitialized = _strPhpUrlPrefix.Trim() != "" &&
                _strPhpUrlDirs.Trim() != "" &&
                BaseParameters.Count > 2;

            if (IsInitialized)
            {
                // collect all received basic parameters (if using multiple fb accs)
                string strFbUid = BaseParameters[PhpCommandParameters.FB_SIG_USER].ToString();
                if (!_BaseParametersListContainsFbUid(strFbUid))
                {
                    BaseParametersList.Add(BaseParameters);
                }

                //Validate User
                _ValidateUserId(strFbUid);
            }
            else
            {
                // if something went wrong, clear base params also
                _strPhpUrlPrefix = "";
                _strPhpUrlDirs = "";
                BaseParameters.Clear();
            }

            return IsInitialized;
        }

        /// <summary>_GetUrlPart</summary>
        /// <param name="ServerId"></param>
        /// <history>14.01.2012</history>
        /// <history>modified 15.01.2012: transferred and adapted from URLItem class</history>
        private static void _GetUrlPart(
            string UrlPart)
        {
            try
            {
                Int32 _intStartIndex = 0;
                Int32 _intEndIndex = UrlPart.IndexOf("www") + 3;

                _strPhpUrlPrefix = UrlPart.Substring(_intStartIndex, _intEndIndex - _intStartIndex);

                _intStartIndex = _intEndIndex;
                _intEndIndex = UrlPart.IndexOf(".", _intStartIndex);

                _intStartIndex = _intEndIndex;

                _strPhpUrlDirs = UrlPart.Substring(_intStartIndex);
                _strPhpUrlDirs = _strPhpUrlDirs.Replace(PhpCommands.getChat.ToString() + ".php", "");
            }
            catch (Exception ex)
            {
                throw ex;
                //_EC.AddException(ex, this.ToString(), _EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_GetParameterDictionary</summary>
        /// <param name="PostParameters"></param>
        /// <returns></returns>
        /// <history>modified 14.10.2011: There was an error when a parameter was double</history>
        /// <history>modified 15.01.2012: transferred and adapted from URLHolder class</history>
        private static Dictionary<String, String> _GetParameterDictionary(
            string PostParameters)
        {
            Dictionary<String, String> dicParameters = new Dictionary<String, String>();

            try
            {
                String[] strParameters = PostParameters.Split('&');

                foreach (String STR in strParameters)
                {
                    String[] strParametersValues = STR.Split('=');

                    if (strParametersValues.Count() == 2)
                    {
                        //14.10.2011: See if a parameter already exists, otherwise there's an error.
                        if (!dicParameters.ContainsKey(strParametersValues[0]))
                        {
                            dicParameters.Add(strParametersValues[0], strParametersValues[1]);
                        }
                        else
                        {
                            dicParameters[strParametersValues[0]] = strParametersValues[1];
                        }
                    }
                }
            }
            catch 
            {
                //_EC.AddException(ex, this.ToString(), _EC.Tools.GetCurrentMethodName());
            }

            return dicParameters;
        }

        /// <summary>_BaseParametersListContainsFbUid</summary>
        /// <param name="FbUid"></param>
        /// <returns>true if a given fbuid already exists in collection</returns>
        /// <history>22.01.2012</history>
        private static bool _BaseParametersListContainsFbUid(
            string FbUid)
        {
            bool fResult = false;

            foreach (Dictionary<string, string> dictParams in BaseParametersList)
            {
                if (dictParams.ContainsKey(PhpCommandParameters.FB_SIG_USER))
                {
                    if (dictParams[PhpCommandParameters.FB_SIG_USER] == FbUid)
                    {
                        return true;
                    }
                }
            }

            return fResult;
        }

        /// <summary>_getBaseParametersListIndexByFbUid</summary>
        /// <param name="FbUid"></param>
        /// <returns></returns>
        /// <history>31.01.2012</history>
        private static int _GetBaseParametersListIndexByFbUid(
            string FbUid)
        {
            int intIndex = 0;
            foreach (Dictionary<string, string> dictParams in BaseParametersList)
            {
                if (dictParams.ContainsKey(PhpCommandParameters.FB_SIG_USER))
                {
                    if (dictParams[PhpCommandParameters.FB_SIG_USER] == FbUid)
                    {
                        return intIndex;
                    }
                }

                intIndex++;
            }

            return 0;
        }

        /// <summary>_RemoveGetChatSpecificParameters</summary>
        /// <history>15.01.2012</history>
        private static void _RemoveGetChatSpecificParameters()
        {
            //Remove getChat.php specific parameters
            BaseParameters.Remove(URLHolder.PARAM_CTYPE);
            BaseParameters.Remove(URLHolder.PARAM_CTYPE_ID);
            BaseParameters.Remove(URLHolder.PARAM_CUR_NEWEST_1);
            BaseParameters.Remove(URLHolder.PARAM_CUR_NEWEST_2);
            BaseParameters.Remove(URLHolder.PARAM_CUR_NEWEST_3);
            BaseParameters.Remove(URLHolder.PARAM_SID);
        }

        /// <summary>_ValidateUserId</summary>
        /// <param name="FbUserId"></param>
        /// <history>created  24.01.2012</history>
        private static void _ValidateUserId(
            string FbUserId)
        {
            UserValidatorItem UVI = new UserValidatorItem();

            //Get item out of dictionary if existing or create a new one
            if (_dictUsers.ContainsKey(FbUserId))
            {
                UVI = _dictUsers[FbUserId];
            }
            else
            {
                UVI.FbUid = FbUserId;
            }

            //get current timestamp
            int intNow = Converters.Date2Timestamp(DateTime.Now);

            //only validate user every INTERVAL_VALIDATE_USER seconds
            if (intNow - UVI.LastCheckedTimestamp > constants.INTERVAL_VALIDATE_USER)
            {
                UVI.UserIsValid = _UserIsValid(FbUserId);
                UVI.LastCheckedTimestamp = Converters.Date2Timestamp(DateTime.Now);
            }

            //finally add item to dictionary if not existing
            if (!_dictUsers.ContainsKey(FbUserId))
            {
                _dictUsers.Add(FbUserId, UVI);
                ThrowNewUserReceivedEvent(new NewUserReceivedEventArgs(UVI));
            }
        }

        /// <summary>_UserIsValid</summary>
        /// <param name="fbuid"></param>
        /// <returns></returns>
        /// <history>25.01.2012 transferred from UserValidator class</history>
        private static bool _UserIsValid(
            string fbuid)
        {
            PostSubmitter PS = new PostSubmitter(constants.CHECK_USER_URL);

            PS.PostItems.Add("action", "exists");
            PS.PostItems.Add("FbUid", fbuid);

            String strResult = PS.Post();

            if (strResult.StartsWith("true"))
            {
                return true;
            }

            return false;
        }
        #endregion

        #region command generating
        /// <summary>_GetPhpCommand</summary>
        /// <param name="SelectCommand"></param>
        /// <param name="ServerId"></param>
        /// <returns></returns>
        /// <history>created  13.01.2012</history>
        /// <history>modified 24.02.2012: added seekKnight and hireKnight</history>
        private static PhpCommand _GetPhpCommand(
            ExceptionCollector EC,
            PhpCommands SelectCommand,
            int ServerId,
            int BaseParametersIndex)
        {
            //get fb user ID
            string strFbUid = ((Dictionary<string, string>)BaseParametersList[BaseParametersIndex])[PhpCommandParameters.FB_SIG_USER];
            UserValidatorItem UVI = _dictUsers[strFbUid];

            //check user validness
            if (UVI != null && UVI.UserIsValid)
            {
                //prepare result
                PhpCommand pcResult = new PhpCommand(EC);

                pcResult.PhpUrlPrefix = _strPhpUrlPrefix;
                pcResult.PhpUrlServerId = ServerId;
                pcResult.PhpUrlDirs = _strPhpUrlDirs;

                //Generate php command string (enum name must be correct)
                pcResult.PhpCommandString = string.Concat(SelectCommand.ToString(), ".php");

                //add base parameters
                _AddBaseParameters(ref pcResult, BaseParametersIndex);

                //add command specific parameters
                switch (SelectCommand)
                {
                    case PhpCommands.getChat:
                        _AddParametersGetChat(ref pcResult);
                        break;
                    case PhpCommands.main_src:
                        break;
                    case PhpCommands.updateSeed:
                        _AddParametersUpdateSeed(ref pcResult);
                        break;
                    case PhpCommands.allianceGetOtherInfo:
                        _AddParametersAllianceGetOtherInfo(ref pcResult);
                        break;
                    case PhpCommands.getUserLeaderboard:
                        _AddParametersGetUserLeaderboard(ref pcResult);
                        break;
                    case PhpCommands.viewCourt:
                        _AddParametersViewCourt(ref pcResult);
                        break;
                    case PhpCommands.getOnline:
                        _AddParametersGetOnline(ref pcResult);
                        break;
                    case PhpCommands.fetchMapTiles:
                        _AddParametersFetchMapTiles(ref pcResult);
                        break;
                    case PhpCommands.myServers:
                        _AddParametersMyServers(ref pcResult);
                        break;
                    case PhpCommands.march:
                        _AddParametersMarch(ref pcResult);
                        break;
                    case PhpCommands.listReports:
                        _AddParametersListReports(ref pcResult);
                        break;
                    case PhpCommands.fetchReport:
                        _AddParametersFetchReport(ref pcResult);
                        break;
                    case PhpCommands.deleteCheckedReports:
                        _AddParametersDeleteCheckedReports(ref pcResult);
                        break;
                    case PhpCommands.skillupKnight:
                        _AddParametersSkillupKnight(ref pcResult);
                        break;
                    case PhpCommands._dispatch:
                        _AddParametersDispatch(ref pcResult);
                        break;
                    case PhpCommands.sendChat:
                        _AddParametersSendChat(ref pcResult);
                        break;
                    case PhpCommands.seekknight:
                        _AddParametersSeekKnight(ref pcResult);
                        break;
                    case PhpCommands.hireKnight:
                        _AddParametersHireKnight(ref pcResult);
                        break;
                    case PhpCommands.hireSpecialKnight:
                        _AddParametersHireSpecialKnight(ref pcResult);
                        break;
                }

                return pcResult;
            }

            return null;
        }

        /// <summary>_AddBaseParameters</summary>
        /// <param name="PC"></param>
        /// <param name="BaseParametersListIndex"></param>
        /// <history>created  13.01.2012</history>
        private static void _AddBaseParameters(
            ref PhpCommand PC,
            int BaseParametersListIndex)
        {
            if (BaseParametersListIndex >= 0 && BaseParametersListIndex < BaseParametersList.Count)
            {
                Dictionary<string, string> dictEntry = BaseParametersList[BaseParametersListIndex] as Dictionary<string, string>;

                if (dictEntry != null)
                {
                    foreach (KeyValuePair<string, string> KVP in dictEntry)
                    {
                        PC.Parameters.Add(KVP.Key, KVP.Value);
                    }
                }
            }
        }

        /// <summary>_AddParametersGetChat</summary>
        /// <param name="PC"></param>
        /// <history>created  13.01.2012</history>
        private static void _AddParametersGetChat(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CTYPE, "");
            PC.Parameters.Add(PhpCommandParameters.CTYPE_ID, "");
            PC.Parameters.Add(PhpCommandParameters.CUR_NEWEST_1, "");
            PC.Parameters.Add(PhpCommandParameters.CUR_NEWEST_2, "");
            PC.Parameters.Add(PhpCommandParameters.CUR_NEWEST_3, "");
            PC.Parameters.Add(PhpCommandParameters.SID, "");
        }

        private static void _AddParametersUpdateSeed(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.FORCE_UPDATE, "");
        }

        private static void _AddParametersAllianceGetOtherInfo(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CITY_ID, "");
        }

        private static void _AddParametersGetUserLeaderboard(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.ALLIANCE_ID, "");
            PC.Parameters.Add(PhpCommandParameters.PER_PAGE, "");
        }

        private static void _AddParametersViewCourt(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.PID, "");
        }

        private static void _AddParametersGetOnline(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CHECK_ARR, "");
        }

        private static void _AddParametersFetchMapTiles(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.BLOCKS, "");
        }

        private static void _AddParametersMyServers(
            ref PhpCommand PC)
        {
            //No Parameters
        }

        private static void _AddParametersMarch(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CID, "");
            PC.Parameters.Add(PhpCommandParameters.TYPE, "");
            PC.Parameters.Add(PhpCommandParameters.KID, "");
            PC.Parameters.Add(PhpCommandParameters.X_COORD, "");
            PC.Parameters.Add(PhpCommandParameters.Y_COORD, "");
            PC.Parameters.Add(PhpCommandParameters.GOLD, "");
            PC.Parameters.Add(PhpCommandParameters.R1, "");
            PC.Parameters.Add(PhpCommandParameters.R2, "");
            PC.Parameters.Add(PhpCommandParameters.R3, "");
            PC.Parameters.Add(PhpCommandParameters.R4, "");
            PC.Parameters.Add(PhpCommandParameters.ITEMS, "");
        }

        private static void _AddParametersListReports(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.PAGE_NO, "");
            PC.Parameters.Add(PhpCommandParameters.GROUP, "");
        }

        private static void _AddParametersFetchReport(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.RID, "");
            PC.Parameters.Add(PhpCommandParameters.SIDE, "");
        }

        private static void _AddParametersDeleteCheckedReports(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CITY_RIDS, "");
            PC.Parameters.Add(PhpCommandParameters.S0_RIDS, "");
            PC.Parameters.Add(PhpCommandParameters.S1_RIDS, "");
        }

        private static void _AddParametersSkillupKnight(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CID, "");
            PC.Parameters.Add(PhpCommandParameters.KID, "");
            PC.Parameters.Add(PhpCommandParameters.P, "");
            PC.Parameters.Add(PhpCommandParameters.C, "");
            PC.Parameters.Add(PhpCommandParameters.I, "");
            PC.Parameters.Add(PhpCommandParameters.R, "");
        }

        private static void _AddParametersDispatch(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CTRL, "");
            PC.Parameters.Add(PhpCommandParameters.ACTION, "");
        }

        private static void _AddParametersSendChat(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.CTYPE, "");
            PC.Parameters.Add(PhpCommandParameters.NAME, "");
            PC.Parameters.Add(PhpCommandParameters.COMMENT, "");
            PC.Parameters.Add(PhpCommandParameters.CTYPE_ID, "");
            PC.Parameters.Add(PhpCommandParameters.NM, "");
            PC.Parameters.Add(PhpCommandParameters.SID, "");
        }

        private static void _AddParametersSeekKnight(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.PID, "");
        }

        private static void _AddParametersHireKnight(
            ref PhpCommand PC)
        {
            PC.Parameters.Add(PhpCommandParameters.FRIEND_PF_ID, "");
            PC.Parameters.Add(PhpCommandParameters.CID, "");
        }

        private static void _AddParametersHireSpecialKnight(
            ref PhpCommand PC)
        {
            if (PC.Parameters[PhpCommandParameters.KRAKEN_NETWORK] == null)
            {
                PC.Parameters.Add(PhpCommandParameters.KRAKEN_NETWORK, "kabamFb");
            }
            PC.Parameters.Add(PhpCommandParameters.CID, "");
            PC.Parameters.Add(PhpCommandParameters.KNAME, "");
        }
        #endregion
        #endregion



        #region interface
        #region properties
        public static Boolean IsInitialized { get; set; }

        public static Dictionary<string, string> BaseParameters = new Dictionary<string, string>();

        public static ArrayList BaseParametersList = new ArrayList();

        public static Dictionary<string, UserValidatorItem> Users
        {
            get
            {
                return _dictUsers;
            }
        }
        #endregion

        #region methods
        public static bool AnalyseUrlGetChat(
            string GetChatUrlPart,
            string GetChatPostData)
        {
            return _AnalyseUrlGetChat(GetChatUrlPart, GetChatPostData);
        }

        public static PhpCommand GetPhpCommand(
            ExceptionCollector EC,
            PhpCommands SelectCommand,
            int ServerId)
        {
            return _GetPhpCommand(EC, SelectCommand, ServerId, 0);
        }

        public static PhpCommand GetPhpCommand(
            ExceptionCollector EC,
            PhpCommands SelectCommand,
            int ServerId,
            int BaseParametersListIndex)
        {
            return _GetPhpCommand(EC, SelectCommand, ServerId, BaseParametersListIndex);
        }

        public static PhpCommand GetPhpCommand(
            ExceptionCollector EC,
            PhpCommands SelectCommand,
            int ServerId,
            string FbUid)
        {
            return _GetPhpCommand(EC, SelectCommand, ServerId, _GetBaseParametersListIndexByFbUid(FbUid));
        }
        #endregion
        #endregion
    }
}
